package org.haredot.context;


import org.haredot.utils.ClassUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/**
 *  负责 将 Classpath 路径下的所有 被 @Component 及其子类注解 注解的类
 *  存入到 一级缓存 和 二级缓存中
 */
public class ClasspathApplicationContext implements ApplicationContext{

    public ClasspathApplicationContext() {
        // 负责去读数据、并填充数据
        try {
            // 1. 从 classpath下读取所有的类
            List<Class<?>> classes = ClassUtils.getClasses();
            // 2. 获取 带有 @Component 注解 及其 子类 注解的所有 类
            classes.stream().filter(clazz -> {
                // 如果当前类对象是 注解，则不要
                if (clazz.isAnnotation()) return false ;
                 // 获取 clazz 类上 所有的注解
                Annotation[] annotations = clazz.getAnnotations();
                // 遍历注解
                for(Annotation annotation : annotations) {
                    // 如果 注解 是 @Component 或者它的子类，则 代表该类是我们需要的
                    if (ClassUtils.isComponent(annotation.annotationType())) return true ;
                }
                return false ;
            }).forEach(clazz -> {
                // clazz 代表 带有 @Component 及其 子类 注解的类
                // 获取 clazz 类上 所有的注解
                Annotation[] annotations = clazz.getAnnotations();
                // 遍历注解
                for(Annotation annotation : annotations) {
                    // 如果 注解 是 @Component 或者它的子类，则 代表该类是我们需要的
                    if (ClassUtils.isComponent(annotation.annotationType())) {
                        // 此时 annotation 就是 @Component 注解 或者它的子类
                        Map<String, String> componentMembers = ClassUtils.getComponentMembers(annotation, clazz.getSimpleName());
                        // 获取 scope 并判断是否 为 singleton
                        String scope = componentMembers.get("scope");
                        String key = componentMembers.get("value") ;
                        // 如果 scope 为 singleton , 则代表 是个单例，创建一个对象，并存储到 一级缓存
                        if ("singleton".equals(scope)) {
                            try {
                                Object o = clazz.getConstructor().newInstance();
                                if (ONE_CACHE_MAP.containsKey(key) || TWO_CACHE_MAP.containsKey(key)) {
                                    throw new ExceptionInInitializerError("bean的ID=" + key + "在容器中已经存在，请检查代码");
                                }else{
                                    ONE_CACHE_MAP.put(key, o) ;
                                }
                            }catch (Exception e) {
                                throw new ExceptionInInitializerError(clazz +" 类中没有提供 公开无参构造方法") ;
                            }
                        } else if ("prototype".equals(scope)) {
                            if (ONE_CACHE_MAP.containsKey(key) || TWO_CACHE_MAP.containsKey(key)) {
                                throw new ExceptionInInitializerError("bean的ID=" + key + "在容器中已经存在，请检查代码");
                            }else{
                                // 将 类对象 存储到 二级缓存中
                                TWO_CACHE_MAP.put(key, clazz) ;
                            }
                        }
                        break ;
                    }
                }
            });

            // 3. 给 容器 管理的 对象 注入 数据

            // 从 一级缓存中， 查找 所有的对象，并获取 对象中的所有 包含 @Resource 注解的 属性
            ONE_CACHE_MAP.values().forEach(this::weaveObj);


        } catch (Exception e) {
            throw new ExceptionInInitializerError(e) ;
        }
    }
}
